//
// JPEG thumbnail decode test
//
// This example sketch decodes an EXIF thumbnail image
// embedded in a 12 megapixel photo taken on a mobile phone
//
// It's written to run on an ESP32 connected to a ILI9341 LCD
// although it can certainly be compiled on other target MCUs and displays
//
#include "WiFi.h"
#include <WiFiManager.h>
#include <time.h>
//如果使用Adafruit字体，则应按下面顺序引用.h文件
#include <bb_spi_lcd.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSansBold24pt7b.h>

#include <ArduinoJson.h>
#include <HTTPClient.h>
#include "JPEGDEC.h"
#include "rgb565_colors.h"
//#include "../test_images/thumb_test.h"
#include "da0.jpg.h"
#include "da1.jpg.h"
#include "da2.jpg.h"
#include "da3.jpg.h"
#include "da4.jpg.h"
#include "da5.jpg.h"
#include "da6.jpg.h"
#include "da7.jpg.h"
#include "da8.jpg.h"
#include "da9.jpg.h"
#include "da10.jpg.h"
#include "da11.jpg.h"
#include "da12.jpg.h"

#include "wea_qing.h"
#include "wea_yin.h"
#include "wea_yu.h"
#include "wea_xue.h"
#include "wea_duoyun.h"

// These pin definitions are for a custom ESP32
// board. Please change them to match the display
// and board you're using

// #define CS_PIN 4
// #define DC_PIN 12
// #define LED_PIN 16
// #define RESET_PIN -1
// #define MISO_PIN 19
// #define MOSI_PIN 23
// #define SCK_PIN 18

// Static instance of the JPEGDEC structure. It requires about
// 17.5K of RAM. You can allocate it dynamically too. Internally it
// does not allocate or free any memory; all memory management decisions
// are left to you
#define TFT_CS 19
#define TFT_RST 22

#define TFT_CS1 19
#define TFT_RST1 22

#define TFT_CS2 18
#define TFT_RST2 23

#define TFT_CS3 17
#define TFT_RST3 5

#define TFT_CS4 4
#define TFT_RST4 16

#define TFT_DC         32
#define TFT_MOSI       25  // Data out
#define TFT_SCLK       26  // Clock out
#define TFT_BL 33 //背光

#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"

JPEGDEC jpeg;

// The LCD display library instance
SPILCD lcd;

const char* ssid1 = "comicyu_2f";
const char* password1 = "67799706100";

const char* ssid = "ChinaNet-yu";
const char* password = "ydd200706";


const uint8_t* digitArr[13] = {(uint8_t*)da0_jpg,(uint8_t*)da1_jpg,(uint8_t*)da2_jpg,(uint8_t*)da3_jpg,(uint8_t*)da4_jpg,(uint8_t*)da5_jpg,(uint8_t*)da6_jpg,
(uint8_t*)da7_jpg,(uint8_t*)da8_jpg,(uint8_t*)da9_jpg,(uint8_t*)da10_jpg,(uint8_t*)da11_jpg,(uint8_t*)da12_jpg};
const int digitLenArr[13]={sizeof(da0_jpg),sizeof(da1_jpg),sizeof(da2_jpg),sizeof(da3_jpg),sizeof(da4_jpg),sizeof(da5_jpg),sizeof(da6_jpg)
,sizeof(da7_jpg),sizeof(da8_jpg),sizeof(da9_jpg),sizeof(da10_jpg),sizeof(da11_jpg),sizeof(da12_jpg)};


String Weather_desc="";
String Weather_temp="";
String Weather_wind="";
String Weather_date="";
String Weather_temp_day="";
String Weather_temp_night="";
String Weather_reportdate="";
String  Weather_desc_day;
String  Weather_desc_night;

int icount=0;
struct tm timeinfo_last;

uint8_t lineBuffer[512]={
  0x07,0xe0
};



// Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS1, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST1);
// Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST2);
// Adafruit_ST7735 tft3 = Adafruit_ST7735(TFT_CS3, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST3);
// Adafruit_ST7735 tft4 = Adafruit_ST7735(TFT_CS4, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST4);

//
// Pixel drawing callback
// called once for each set of MCUs (minimum coded units).
// JPEGDEC will try to send as many pixels as it can per call.
// In this case, it's as many as can fit in
// the internal 4K pixel buffer. This allows it to run more
// efficiently than calling this for every MCU. For this demo, the
// MCUs are only 4x4 pixels each since we ask to decode the image
// at 1/4 size
//

void fillLineBuffer(uint8_t vh,uint8_t vl)
{
  for(int i=0;i<512/2;i++)
  {
    lineBuffer[i]=vh;
    lineBuffer[i+1]=vl;
  }
}

int drawMCUs(JPEGDRAW *pDraw)
{
  int iCount;
  iCount = pDraw->iWidth * pDraw->iHeight; // number of pixels to draw in this call
//  Serial.printf("Draw pos = %d,%d. size = %d x %d\n", pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
  spilcdSetPosition(&lcd, pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, DRAW_TO_LCD);
  spilcdWriteDataBlock(&lcd, (uint8_t *)pDraw->pPixels, iCount*2, DRAW_TO_LCD | DRAW_WITH_DMA);
  return 1; // returning true (1) tells JPEGDEC to continue decoding. Returning false (0) would quit decoding immediately.
} /* drawMCUs() */

void setup()
{
  Serial.begin(115200);
  pinMode(TFT_CS,OUTPUT);
  pinMode(TFT_CS2,OUTPUT);
  pinMode(TFT_CS3,OUTPUT);
  pinMode(TFT_CS4,OUTPUT);

  pinMode(TFT_RST,OUTPUT);
  pinMode(TFT_RST2,OUTPUT);
  pinMode(TFT_RST3,OUTPUT);
  pinMode(TFT_RST4,OUTPUT);

  fillLineBuffer(0x07,0xe0);
  resetDisps();
//initScreens();


  delay(1000);

  enableAll();
  spilcdInit(&lcd, LCD_ST7735R, FLAGS_NONE, 40000000,   TFT_CS, 32, TFT_RST, 33, -1, 25, 26,1); // ST7735R
  delay(1000);
  
  //spilcdInit(&lcd2, LCD_ST7735R, FLAGS_NONE, 40000000,   18, 32, 23, 33, -1, 25, 26,1); // ST7735R
  // spilcdInit(&lcd3, LCD_ST7735R, FLAGS_NONE, 40000000,   17, 32, 5, 33, -1, 25, 26,1); // ST7735R
  // spilcdInit(&lcd4, LCD_ST7735R, FLAGS_NONE, 40000000,   4, 32, 16, 33, -1, 25, 26,1); // ST7735R
  //spilcdSetOrientation(&lcd, LCD_ORIENTATION_90);
  spilcdFill(&lcd, 0, DRAW_TO_LCD); // erase display to black
  //spilcdWriteString(&lcd, 0,0,(char *)"Bruce Timer", 0x7e0,0,FONT_8x8, DRAW_TO_LCD);
  spilcdWriteString(&lcd, 0,0,(char *)"Bruce Timer", 0xffff,0,FONT_8x8, DRAW_TO_LCD);
  delay(1000);
  
  //spilcdFill(&lcd2, 0, DRAW_TO_LCD); // erase display to black
  // spilcdFill(&lcd3, 0, DRAW_TO_LCD); // erase display to black
  // spilcdFill(&lcd4, 0, DRAW_TO_LCD); // erase display to black
  

//屏幕初始化完成
//wifi,时间初始化

  printBoth("Connect to Wifi.");
  connectWifi();
  printBoth("Connected.");
  delay(1000);
  printBoth("Getting time ...");
  configTime(8*3600,0,NTP1,NTP2,NTP3);
  struct tm timeinfo;
  while(!getLocalTime(&timeinfo, 3000))
  {
    delay(1000); 
    printBoth(".");   
  }
  Serial.println("Got time.");
  
  enableAll();
  spilcdFill(&lcd, 0, DRAW_TO_LCD); // erase display to black
  //show0to9();
  delay(1000);
} /* setup() */

void printBoth(const char* str)
{
  Serial.print(str);
  spilcdWriteString(&lcd,0,50,(char *)str,0x7e0,0,FONT_8x8, DRAW_TO_LCD);
}

void resetDisps()
{
  digitalWrite(TFT_RST,HIGH);
  digitalWrite(TFT_RST,LOW);

  digitalWrite(TFT_RST2,HIGH);
  digitalWrite(TFT_RST2,LOW);

  digitalWrite(TFT_RST3,HIGH);
  digitalWrite(TFT_RST3,LOW);

  digitalWrite(TFT_RST4,HIGH);
  digitalWrite(TFT_RST4,LOW);

  delay(100);

  digitalWrite(TFT_RST,HIGH);
  digitalWrite(TFT_RST2,HIGH);
  digitalWrite(TFT_RST3,HIGH);
  digitalWrite(TFT_RST4,HIGH);
}

void enableDisp(int index)
{
  digitalWrite(TFT_CS,HIGH);
  digitalWrite(TFT_CS2,HIGH);
  digitalWrite(TFT_CS3,HIGH);
  digitalWrite(TFT_CS4,HIGH);

  if(index==0){lcd.iCSPin=TFT_CS1;}
  if(index==1){lcd.iCSPin=TFT_CS2;}
  if(index==2){lcd.iCSPin=TFT_CS3;}
  if(index==3){lcd.iCSPin=TFT_CS4;}
}

void enableAll()
{
  digitalWrite(TFT_CS,LOW);
  digitalWrite(TFT_CS2,LOW);
  digitalWrite(TFT_CS3,LOW);
  digitalWrite(TFT_CS4,LOW);
}


void showjpg(uint8_t * pjpg_img,int size,int x=0,int y=0)
{
  long lTime;
  char szTemp[64];

  // Open a large JPEG image stored in FLASH memory (included as thumb_test.h)
  // This image is 12 megapixels, but has a 320x240 embedded thumbnail in it
  if (jpeg.openFLASH((uint8_t *)pjpg_img, size, drawMCUs))
  {
    //Serial.println("Successfully opened JPEG image");
    //Serial.printf("Image size: %d x %d, orientation: %d, bpp: %d\n", jpeg.getWidth(),
    //  jpeg.getHeight(), jpeg.getOrientation(), jpeg.getBpp());

    // if (jpeg.hasThumb())
    //    Serial.printf("Thumbnail present: %d x %d\n", jpeg.getThumbWidth(), jpeg.getThumbHeight());
    jpeg.setPixelType(RGB565_BIG_ENDIAN); // The SPI LCD wants the 16-bit pixels in big-endian order
    lTime = micros();
    // Draw the thumbnail image in the middle of the display (upper left corner = 120,100) at 1/4 scale
    if (jpeg.decode(x,y,JPEG_AUTO_ROTATE))
    {
      lTime = micros() - lTime;
      //sprintf(szTemp, "Successfully decoded image in %d us", (int)lTime);
      //Serial.println(szTemp);
      //spilcdWriteString(&lcd, 0, 200, szTemp, 0xffe0, 0, FONT_8x8, DRAW_TO_LCD);
    }
    jpeg.close();
  }
  else
    Serial.println("open jpg failed.");
}

#define SHOWJPG(x) showjpg((uint8_t *) x,sizeof(x),0,0)
void show0to9()
{
  SHOWJPG(da0_jpg);
  SHOWJPG(da1_jpg);
  //SHOWJPG(da2_jpg);
  //SHOWJPG(da3_jpg);
  SHOWJPG(da4_jpg);
  SHOWJPG(da5_jpg);
  //SHOWJPG(da6_jpg);
  //SHOWJPG(da7_jpg);
  SHOWJPG(da8_jpg);
  //SHOWJPG(da9_jpg);
}

void showDigit(int digit,int dispIndex)
{
  
  enableDisp(dispIndex);
  clearDisp();
  //show0to9();
  //showjpg((uint8_t*)digitArr[digit],digitLenArr[digit]);
  String sdigit=String(digit);
  spilcdWriteStringCustom(&lcd, (GFXfont *)&FreeSansBold24pt7b, 10, 60, (char*) sdigit.c_str(), RGB565_Blue, 0, 1, DRAW_TO_LCD);   
}


int ic=0;
int firstShow=0;

void loop() {
 if(ic%120==0)
  {
    getWeather();
  }
  
  printLocalTime();
  //ic=(ic+1)%600;
  ic=(ic+1)%3000;
  delay(2000);

  // if(ic%2==0)
  // {
  //   // u8g2_2.setCursor(dotx,120);
  //   // u8g2_2.print("■");
  //   // u8g2_2.setCursor(dotx,60);
  //   // u8g2_2.print("■");

  //   // u8g2_3.setCursor(-7,120);
  //   // u8g2_3.print("■");
  //   // u8g2_3.setCursor(-7,60);
  //   // u8g2_3.print("■");
  // }
  // else
  // {
  //   //清屏两点部分
  //   //tft2.fillRect(dotx,40,10,100,ST77XX_BLACK);
  //   // tft3.fillRect(0,40,10,100,ST77XX_BLACK);
  // }


// long lTime = micros();
// for(int i=0;i<100;i++){
//   showDigit(i%10,i%4); 
//   delay(1000);
  // enableDisp(0);
  // show0to9();SHOWJPG(da0_jpg); delay(1000);
  // enableDisp(1);
  // show0to9();SHOWJPG(da1_jpg); delay(1000);
  // enableDisp(2);
  // show0to9();SHOWJPG(da2_jpg); delay(1000);
  // enableDisp(3);
  // show0to9();SHOWJPG(da3_jpg); delay(1000);
  // enableDisp(0);
  // show0to9();SHOWJPG(da4_jpg); delay(1000);
  // enableDisp(1);
  // show0to9();SHOWJPG(da5_jpg); delay(1000);
  // enableDisp(2);
  // show0to9();SHOWJPG(da6_jpg); delay(1000);
  // enableDisp(3);
  // show0to9();SHOWJPG(da7_jpg); delay(1000);
  // enableDisp(0);
  // show0to9();SHOWJPG(da8_jpg); delay(1000);
  // enableDisp(1);
  // show0to9();SHOWJPG(da9_jpg); delay(1000);
  
  //spilcdFill(&lcd, 0, DRAW_TO_LCD); // erase display to black
  //delay(1000); // repeat every 10 seconds
// }
// long totalTime = (micros()-lTime)/1000;
// Serial.print("1000 frames sonsume time(ms):");
// Serial.println(totalTime);
// Serial.print("fps:");
// Serial.println(1000*1000/totalTime);

}



void connectWifi()
{
  int ic=0;
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

while (WiFi.status() != WL_CONNECTED)
{
  printBoth("Connect to Wifi:");
  printBoth(ssid);
  ic=0;
  WiFi.begin(ssid, password);
  delay(1000);
  while (WiFi.status() != WL_CONNECTED && ic<20) {  
    printBoth("-");
    delay(1000);
    ic++;
  }
  
  if(WiFi.status() != WL_CONNECTED)
  {
  ic=0;

  printBoth("Change to Wifi:");
  printBoth(ssid1);

  WiFi.begin(ssid1, password1);
  delay(1000);
  while (WiFi.status() != WL_CONNECTED && ic<10) {  
    printBoth("-");
    delay(1000);
    ic++;
  }
  }
}

  //u8g2.setCursor(_x(0),_y(0));
  printBoth("WiFi connected!");

//------------Wifi Manager-----------------//
//   WiFiManager wm;
//   tft.println("Trying to connect to WiFi...");
//   tft.setFont(&FreeSansBold24pt7b);
//  bool response = wm.autoConnect(ssid, password);
//   if (!response) {
//     Serial.println("Failed to connect. Retrying connection ...");
//     //Try again in 5s.
//     ESP.restart();
//     delay(3000);
//   } 
//   else 
//   {
//     Serial.println("Connected to wifi with IP: ");
//     String ip = WiFi.localIP().toString();
//     Serial.println(WiFi.localIP());
//   }
}


// void initScreens()
// {
//   tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
//   tft.fillScreen(ST77XX_BLACK);
//   tft2.initR(INITR_BLACKTAB);
//   tft2.fillScreen(ST77XX_BLACK);
//   tft3.initR(INITR_BLACKTAB);
//   tft3.fillScreen(ST77XX_BLACK);
//   tft4.initR(INITR_BLACKTAB);
//   tft4.fillScreen(ST77XX_BLACK);
// }

void getWeather()
{

  
      String wea = getWeatherReq("base");
      if(wea.length()>0)
      {
        StaticJsonDocument<300> doc;
        deserializeJson(doc,wea);
      
        Weather_desc=String((const char *)doc["lives"][0]["weather"]);
        Weather_temp=String((const char *)doc["lives"][0]["temperature"]);
        Weather_wind=String((const char *)doc["lives"][0]["winddirection"])+String((const char *)doc["lives"][0]["windpower"]);
        Weather_reportdate=String((const char *)doc["lives"][0]["reporttime"]).substring(0,10);
      }
      
      if(Weather_date!=Weather_reportdate)
      {
        wea = getWeatherReq("all");
        if(wea.length()>0)
        {
          StaticJsonDocument<1500> doc;
          deserializeJson(doc,wea);
          Serial.println(wea);
          Weather_date=String((const char *)doc["forecasts"][0]["casts"][0]["date"]);
          Weather_desc_day=String((const char *)doc["forecasts"][0]["casts"][0]["dayweather"]);
          Weather_desc_night=String((const char *)doc["forecasts"][0]["casts"][0]["nightweather"]);
          Weather_temp_day=String((const char *)doc["forecasts"][0]["casts"][0]["daytemp"]);
          Weather_temp_night=String((const char *)doc["forecasts"][0]["casts"][0]["nighttemp"]);
        }
      }
    enableDisp(0);
    clearDisp();
}

String getWeatherReq(String base)
{
  String result="";
  Serial.println("Getting weather ...");
  String url = "https://restapi.amap.com/v3/weather/weatherInfo?parameters&key=e094cccaa9f94c734344ab015d8b4ec6&city=110000&extensions="+base+"&output=JSON";
  HTTPClient http;
  http.begin(url);
  int httpCode=http.GET();
  if(httpCode>0)
    result = http.getString();
  Serial.println(result);
  return result;
}

void drawPixels(SPILCD* plcd,uint8_t* ppixels, int x,int y,int w,int h)
{
  int iCount;
  iCount = w * h; // number of pixels to draw in this call
//  Serial.printf("Draw pos = %d,%d. size = %d x %d\n", pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
  spilcdSetPosition(plcd, x, y, w, h, DRAW_TO_LCD);
  spilcdWriteDataBlock(plcd, ppixels, iCount*2, DRAW_TO_LCD | DRAW_WITH_DMA);
}

void printLocalTime() {
  


  time_t now;
  now=time(NULL);
  
  struct tm * ltm=localtime(&now);

  {
    // 成功获取时间，格式化并打印
    if(firstShow==0)
    {
      firstShow++;
    }
    //String currentTime = String(asctime(&timeinfo));
    String currentTime = String(asctime(ltm));
    currentTime.trim(); // 移除字符串尾部的换行符
    Serial.println("Show Hour");
    printDigitHour(ltm->tm_hour,timeinfo_last.tm_hour,timeinfo_last.tm_hour==0 ||ltm->tm_sec==0);
    Serial.println("Show Min");
    printDigitMin(ltm->tm_min,timeinfo_last.tm_min,timeinfo_last.tm_min==0 ||ltm->tm_sec==0);

    //显示天气
  // u8g2.setCursor(0,50);
  // //tft.setCursor(10,50);
  // u8g2.println("北京天气:");
  // u8g2.println(Weather_date);
  // //u8g2.println(Weather_desc);
  // u8g2.println( Weather_desc_day + "-" +  Weather_desc_night);
  // u8g2.println(Weather_temp+" ("+ Weather_temp_day + "-" + Weather_temp_night +")");
  // u8g2.println(Weather_wind);

    #define SHOWImg(img,x,y) showjpg(((uint8_t*)img),sizeof(img),(x),(y))

    int weax=10;
    int weay=30;
    
    enableDisp(0);
    if(Weather_desc.indexOf("晴")>=0)
      SHOWImg(wea_qing,weax,weay);
    else if (Weather_desc.indexOf("阴")>=0)
      SHOWImg(wea_yin,weax,weay);
    else if (Weather_desc.indexOf("雨")>=0)
      SHOWImg(wea_yu,weax,weay);
    else if (Weather_desc.indexOf("雪")>=0)
      SHOWImg(wea_xue,weax,weay);
    else
      SHOWImg(wea_duoyun,weax,weay);

    spilcdWriteString(&lcd, weax,100,(char*)Weather_temp.c_str(), 0xffff,0,FONT_16x16, DRAW_TO_LCD);
    String tempRange = Weather_temp_day+"-"+Weather_temp_night;
    spilcdWriteString(&lcd, weax,120,(char*)tempRange.c_str(), 0xffff,0,FONT_8x8, DRAW_TO_LCD);

    //划绿色线
    // int sec =ltm->tm_sec;
    // int section = sec/15;
    // Serial.printf("sec=%d,section=%d",sec,section);
    // for(int i=0;i<section;i++)
    // {
    //   enableDisp(i);
    //   drawPixels(&lcd,lineBuffer,0,0,128,2);
    // }
    timeinfo_last.tm_hour = ltm->tm_hour;
    timeinfo_last.tm_min = ltm->tm_min;
  }
}

void printDigitHour(int h,int lasth,bool clearScr)
{
  Serial.printf("print digit hour %d \r\n",h);
  //int h1 = (h>12?h-12:h)/10;
  //int h2 = (h>12?h-12:h)%10;

   if(lasth!=h)
   {
    //showDigit(h1,0);
    showDigit(h>12?h-12:h,1);
   }
    
  
  
}

void printDigitMin(int v,int lastv,bool clearScr)
{
  Serial.printf("print digit min %d \r\n",v);
  int v1 = v/10;
  int v2 = v%10;
  //if(v!=lastv)
  {
    showDigit(v1,2);
  }
  showDigit(v2,3);
}

void clear(int index)
{
  enableDisp(index);
  clearDisp();
}

void clearDisp()
{
  spilcdFill(&lcd, 0, DRAW_TO_LCD);
}

void clearDispAll()
{
    enableDisp(0);
    clearDisp();

    enableDisp(1);
    clearDisp();

    enableDisp(2);
    clearDisp();

    enableDisp(3);
    clearDisp();
}

